package timbap.artwork.retrieval;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.HttpMethodRetryHandler;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.params.HttpClientParams;
import org.apache.commons.httpclient.params.HttpMethodParams;
import timbap.artwork.util.HttpGetBufferRegistry;
import timbap.visualizer.api.plugin.configuration.binding.ResultSet;
import timbap.visualizer.api.plugin.configuration.binding.ResultType;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;

public class YahooArtworkRetrieverImpl implements ArtworkRetriever {

    private static final String PLUGINS_BASE_PACKAGE = "timbap.visualizer.api.plugin.configuration.binding";
    private static final String YAHOO_IMAGE_SEARCH_BASE_URL = "http://search.yahooapis.com/ImageSearchService/V1/imageSearch";
    private static final String YAHOO_IMAGESEARCH_APPID = "z4ag79_V34GIE.mqa46529Y84AEeq.fWf2t.WIuzNxrXoEwa_HlwrU_KWeIFRXw-";

    private HttpClient httpClient;

    public YahooArtworkRetrieverImpl() {
        HttpMethodRetryHandler tRetryHandler = new HttpMethodRetryHandler() {
            public boolean retryMethod(final HttpMethod method, final IOException exception, final int executionCount) {
                return executionCount < 2;
            }
        };
        HttpClientParams tParams = new HttpClientParams();
        tParams.setConnectionManagerTimeout(3000);
        tParams.setParameter(HttpMethodParams.RETRY_HANDLER, tRetryHandler);
        httpClient = new HttpClient(tParams, new MultiThreadedHttpConnectionManager());
    }

    public InputStream retrieveImageFromUrl(String pImageUrl) {
        return prepareHttpGetRequest(pImageUrl);
    }

    public List<String> performSearch(final String pQueryString) {
        try {
            String tEncodedQueryString = URLEncoder.encode(pQueryString, "UTF8");
            String tSearchUrl = YAHOO_IMAGE_SEARCH_BASE_URL
                    + "?appid=" + YAHOO_IMAGESEARCH_APPID
                    + "&query=" + tEncodedQueryString
                    + "&format=jpeg&results=50";
            InputStream tInputStream = prepareHttpGetRequest(tSearchUrl);
            return parseUrlsFromSearchResult(tInputStream);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }

    private InputStream prepareHttpGetRequest(String pRequestUrl) {
        GetMethod tGetMethod = new GetMethod(pRequestUrl);

        InputStream tHttpResultStream = null;
        try {
            // Execute the method.
            int tStatusCode = httpClient.executeMethod(tGetMethod);
            if (tStatusCode != HttpStatus.SC_OK) {
                System.err.println("Method failed: " + tGetMethod.getStatusLine());
            }
            // Read the response body.
            tHttpResultStream = tGetMethod.getResponseBodyAsStream();

        } catch (Exception e) {
            System.err.println("Error in http get of " + pRequestUrl + ": " + e.getMessage());
            e.printStackTrace();
        } finally {
            // Prepare to release the connection later.
            HttpGetBufferRegistry.getInstance().register(tHttpResultStream, tGetMethod);
        }
        return tHttpResultStream;

    }

    private List<String> parseUrlsFromSearchResult(InputStream pSearchResultStream) {
        final List<String> tImageUrls = new ArrayList<String>();
        try {
            JAXBContext tJAXBContext = JAXBContext.newInstance(PLUGINS_BASE_PACKAGE);
            Unmarshaller tUnmarshaller = tJAXBContext.createUnmarshaller();
            ResultSet tResultSet = (ResultSet)tUnmarshaller.unmarshal(pSearchResultStream);
            for (ResultType tResult : tResultSet.getResults()) {
                float tAspectRatio = tResult.getWidth().floatValue() / tResult.getHeight().floatValue();
                if (tResult.getWidth().intValue() > 100 && tAspectRatio < 1.2 && tAspectRatio > 0.98) {
                    tImageUrls.add(tResult.getUrl());
                }
            }
        } catch (JAXBException e) {
            e.printStackTrace();
        } finally {
            HttpGetBufferRegistry.getInstance().release(pSearchResultStream);
        }
        return tImageUrls;
    }

}
